#ifndef XTOOLS_H
#define XTOOLS_H

#ifdef _WIN32
#ifdef XCODEC_EXPORTS
#define XCODEC_API __declspec(dllexport)
#else
#define XCODEC_API __declspec(dllimport)
#endif // XCODEC_EXPORTS
#else
#define XCODEC_API
#endif // _WIN32

#include <iostream>
#include <list>
#include <mutex>
#include <thread>


///////////////////// 日志 ///////////
// 日志级别
enum XLogLevel {
  XLOG_TYPE_DEBUG,
  XLOG_TYPE_INFO,
  XLOG_TYPE_ERROR,
  XLOG_TYPE_FATAL,
};
constexpr int LOG_MIN_LEVEL = 0;

#define XLOG(s, level)                                                         \
  if ((level) > LOG_MIN_LEVEL)                                                 \
  std::cout << level << __FILE__ << ":" << __LINE__ << ":" << s << std::endl;

#define LOGDEBUG(s) XLOG(s, XLOG_TYPE_DEBUG)
#define LOGINFO(s) XLOG(s, XLOG_TYPE_INFO)
#define LOGERROR(s) XLOG(s, XLOG_TYPE_ERROR)
#define LOGFATAL(s) XLOG(s, XLOG_TYPE_FATAL)
///////////////////// 结束日志 ///////////
XCODEC_API void MSleep(unsigned int ms);

// 获取当前时间戳 毫秒
XCODEC_API long long NowMs();

struct AVPacket;
struct AVCodecParameters;
struct AVRational;
struct AVFrame;
struct AVCodecContext;

XCODEC_API void PrintErr(int err);

XCODEC_API void XFreeFrame(AVFrame **frame);

XCODEC_API long long XResacle(long long pts, AVRational*src_time_base, AVRational*des_time_base);

class XCODEC_API XThread {
public:
  virtual ~XThread() {}
  // 启动线程
  virtual void Start();
  // 线程退出标志位，如果为true那么表示因该退出，需要在入口函数做处理
  bool is_exit() const{ return is_exit_; }
  // 线程退出, 只是设置退出标志位为true，
  // 具体退出需要在Main函数中处理，
  // Main在检测到is_exit_为true时退出
  // 需要调用Wait等待线程退出
  virtual void Exit() {
    is_exit_ = true;
  }
  // 设置线程退出标志位为true，
  virtual void Stop();
  // 并等待线程退出
  virtual void Wait();
  // 执行责任
  virtual void Do(AVPacket *pkt) {};
  // 传递到下一个节点
  virtual void Next(AVPacket *pkt) {
    std::unique_lock<std::mutex> lg(m_);
    if (next_) {
      next_->Do(pkt);
    }
  }
  // 设置责任链下一个节点（线程安全）
  void set_next(XThread *next) {
    std::unique_lock<std::mutex> lg(m_);
    next_ = next;
  }
  // 暂停/播放
  virtual void Pause(bool is_pause){is_pause_ = is_pause;}
  // 是否暂停
  bool is_pause()const { return is_pause_; }

protected:
    bool is_pause_ = false;     // 是否暂停
  // 线程入口函数
  virtual void Main() = 0;
  bool is_exit_ = false;
  int index_ = 0;

private:
  std::thread th_;
  std::mutex m_;
  XThread *next_ = nullptr; // 责任链下一个节点
};

class XCODEC_API XPara {
public:
  virtual ~XPara();
  static XPara *Create();
  AVCodecParameters *para = nullptr; // 音视频参数
  AVRational *time_base = nullptr;   // 时间基数
  long long total_ms = 0;            // 总时长 毫秒
private:
  XPara();
};

// 线程安全的队列
class XCODEC_API XAVPacketList {
public:
  // 获取一个数据，需要用户自己维护AVPacket*
  AVPacket *Pop();
  // 添加一个数据，只是对pkt进行引用，不会进行复制
  void Push(AVPacket *pkt);

  int Size();

  void Clear();

private:
  std::mutex m_;
  std::list<AVPacket *> pkts_;
  int max_packets_ = 1000; // 最大列表数量，超出清理
  int min_packets_ = 10;  // 最小列表数量，低于这个数量
};
#endif // XTOOLS_H
